package vip.xiaonuo.modular.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.java.Log;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import vip.xiaonuo.core.dbs.CurrentDataSourceContext;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.exception.enums.ServerExceptionEnum;
import vip.xiaonuo.modular.business.adapter.IndexDataAnalysis.AbstractAdapter;
import vip.xiaonuo.modular.business.entity.BiIndexData.IndexDataSumVo;
import vip.xiaonuo.modular.business.entity.BiIndexData.IndexDataVo;
import vip.xiaonuo.modular.business.entity.BiIndexData.IndexValueScope;
import vip.xiaonuo.modular.business.entity.BiIndexData.QueryVo;
import vip.xiaonuo.modular.business.param.BiIndexData.QueryParam;
import vip.xiaonuo.modular.business.service.IndexDataManageService;
import vip.xiaonuo.modular.business.service.UserIndexColorService;
import vip.xiaonuo.modular.cache.IndexDataRecordCache;
import vip.xiaonuo.modular.cache.PoiQueryCache;
import vip.xiaonuo.modular.common.DistanceHelper;
import vip.xiaonuo.modular.common.GridColorUtils;
import vip.xiaonuo.modular.common.WdAnalysisConst;
import vip.xiaonuo.modular.enums.IndexAnalysisEnum;
import vip.xiaonuo.modular.enums.IndexLevelEnum;
import vip.xiaonuo.modular.manage.biCountryProfile.entity.BiCountryProfile;
import vip.xiaonuo.modular.manage.biindexdata.entity.BiIndexData;
import vip.xiaonuo.modular.manage.biindexdata.mapper.BiIndexDataMapper;
import vip.xiaonuo.modular.manage.biindexdata.param.BiIndexDataParam;
import vip.xiaonuo.modular.manage.biindexdata.service.BiIndexDataService;
import vip.xiaonuo.modular.manage.biindexdatasum.entity.BiIndexDataSum;
import vip.xiaonuo.modular.manage.biindexdatasum.param.BiIndexDataSumParam;
import vip.xiaonuo.modular.manage.biindexdatasum.service.BiIndexDataSumService;
import vip.xiaonuo.modular.manage.biindexfunction.entity.BiIndexFunction;
import vip.xiaonuo.modular.manage.biindexfunction.param.BiIndexFunctionParam;
import vip.xiaonuo.modular.manage.biindexfunction.service.BiIndexFunctionService;
import vip.xiaonuo.modular.manage.biindextype.entity.BiIndexType;
import vip.xiaonuo.modular.manage.biindextype.service.BiIndexTypeService;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author cy
 * @Date 2022/8/4 15:08
 * @Version 1.0
 */
@Log
@Service
public class IndexDataManageServiceImpl implements IndexDataManageService {
    @Autowired
    private ApplicationContext applicationContext;
    @Resource
    private BiIndexDataSumService biIndexDataSumService;
    @Resource
    private BiIndexDataService biIndexDataService;
    @Resource
    private BiIndexFunctionService biIndexFunctionService;

    @Resource
    private BiIndexDataMapper biIndexDataMapper;

    @Resource
    private BiIndexTypeService biIndexTypeService;

    @Resource
    private UserIndexColorService userIndexColorService;

    @Resource
    private PoiQueryCache poiQueryCache;


    public Object indexIntroduce(QueryParam param) {
        Long typeId = param.getTypeId();
        if (typeId != null ) {
            throw new ServiceException(9,"指标id不能为空");
        }
        JSONObject cacheObject = poiQueryCache.get("indexIntroduce" + typeId);
        if (cacheObject != null) {
            return cacheObject;
        }

        BiIndexType type = biIndexTypeService.getById(typeId);
        if (type == null) {
            throw new ServiceException(9,"没有找到指标id："+typeId);
        }
        JSONObject result = new JSONObject();
        result.put("name", type.getName());
        result.put("description", type.getDescription());

        BiIndexFunction biIndexFunction = biIndexFunctionService.lambdaQuery()
                .eq(BiIndexFunction::getIndexTypeId,param.getTypeId())
                .last(" limit 1 ").one();
        if (biIndexFunction != null) {
            result.put("functionMsg",biIndexFunction.getFunctionMsg());
            result.put("imageUrl",biIndexFunction.getImageUrl());
        }

//        CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
//        BiIndexDataParam dataParam = new BiIndexDataParam();
//        BeanUtil.copyProperties(param,dataParam);
//        //总栅格数
//        Long number = biIndexDataMapper.queryGridNumber(dataParam);
//        result.put("number",number);
//        //最大值、最小值
//        String max = biIndexDataMapper.queryGridMaxValue(dataParam);
//        String min = biIndexDataMapper.queryGridMinValue(dataParam);
//        result.put("max",max);
//        result.put("min",min);
//        CurrentDataSourceContext.clearDataSourceType();
        poiQueryCache.put("indexIntroduce" + typeId,result);
        return result;
    }

    @Resource
    private IndexDataRecordCache indexDataRecordCache;
    public JSONArray queryIndexData(QueryParam param) {
        log.info("开始查询指标数据："+JSONObject.toJSONString(param));
        long startTime = System.currentTimeMillis();
        List<Long> typeIds = param.getTypeIds();
        if (CollectionUtil.isEmpty(typeIds) && param.getCurrentTargetId() == null) {
            throw new ServiceException(9, "指标编号列表typeIds不能为空");
        }
        if (param.getCurrentTargetId() == null) {
            param.setCurrentTargetId(typeIds.get(0));
        }else if(CollectionUtil.isEmpty(typeIds) ){
            typeIds = Arrays.asList(param.getCurrentTargetId());
        }
        Long[] longs = typeIds.toArray(new Long[typeIds.size()]);
        param.setTypeIds(null);
        this.trimLngLat(param);

        JSONArray result = new JSONArray();
        for (Long typeId : longs) {
            String key = "index"+typeId + JSONObject.toJSONString(param);
            JSONObject cacheObject = poiQueryCache.get(key);
            if (cacheObject == null) {
                cacheObject = selectIndexData(param,typeId);
            }
            result.add(cacheObject);
        }
        log.info("查询指标数据完成，耗时:"+(System.currentTimeMillis()-startTime));
        return result;
    }

    private JSONObject selectIndexData(QueryParam param,long typeId){
        String color = userIndexColorService.getIndexColor(typeId);
        BiIndexType indexType = biIndexTypeService.getById(typeId);
        if(indexType == null){
            return null;
        }

        BiIndexDataParam biIndexDataParam = new BiIndexDataParam();
        BeanUtils.copyProperties(param, biIndexDataParam);
        if (param.getYear() != null) {
            biIndexDataParam.setYear(String.valueOf(param.getYear()));
        }
        biIndexDataParam.setTypeId(typeId);

        if (param.getScale() != null) {
            String sampleSQL = DistanceHelper.calcSampleSQL(param.getScale(),10,12.8);
            biIndexDataParam.setSampleSQL(sampleSQL);
        }

        List<BiIndexData> biIndexData = new ArrayList<>();
        //只有当前选择的指标才查询具体的网格数据
        if(typeId == param.getCurrentTargetId()){
            CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
            biIndexData = biIndexDataMapper.selectListCustom(biIndexDataParam);
            CurrentDataSourceContext.clearDataSourceType();
        }
        if (param.getCustomPolygons() != null) {
            //自定义多边形 需要过滤范围之外的网格数据
            List<BiIndexData> newBiIndexData = new ArrayList<>();
            for(BiIndexData d : biIndexData){
                boolean inPoly = DistanceHelper.isPtInPoly(
                        new Point2D.Double(Double.parseDouble(d.getLng()), Double.parseDouble(d.getLat())),
                        param.getCustomPolygons());
                if(inPoly){
                    newBiIndexData.add(d);
                }
            }
            biIndexData = newBiIndexData;
        }

        List<String> colorLevel = GridColorUtils.getColorLevel(color);
        double max = biIndexData.stream().mapToDouble(
                el -> StringUtils.hasText(el.getValue())
                        ? Double.parseDouble(el.getValue()):0
        ).max().orElse(0);
        double min = biIndexData.stream().mapToDouble(
                el -> StringUtils.hasText(el.getValue())
                        ? Double.parseDouble(el.getValue()):0
        ).min().orElse(0);

        JSONArray pointArray = new JSONArray();
        for (BiIndexData d : biIndexData) {
            JSONObject point = new JSONObject();
            point.put("multipolygonArray",biIndexDataService.changeMultipolygon(d.getMultipolygon()));
            point.put("value", d.getValue());
            point.put("grid", d.getGrid());
            String colorByValue = GridColorUtils.getColorByValue(colorLevel, max, min, d.getValue());
            point.put("color", colorByValue);
            pointArray.add(point);
        }

        JSONObject obj = new JSONObject();
        obj.put("typeId", typeId);
        obj.put("name", indexType.getName());
        obj.put("list",pointArray);
        obj.put("colorLevel", colorLevel);
        obj.put("valueRange", GridColorUtils.getValueRange(colorLevel,max,min));
        return obj;
    }

    @Override
    public Object indexDataList(QueryParam param) {
        QueryVo queryVo = new QueryVo();

        //level=1,2,3时查询bi_index_data_sum表，level=4,5时展示bi_index_data表
        if(IndexLevelEnum.PROVINCE.getCode()==param.getLevel()||
           IndexLevelEnum.CITY.getCode()==param.getLevel()||
           IndexLevelEnum.COUNTRY.getCode()==param.getLevel()) {
            BiIndexDataSumParam dataSumParam = new BiIndexDataSumParam();
            BeanUtils.copyProperties(param,dataSumParam);
            List<BiIndexDataSum> dataSumList = biIndexDataSumService.indexDataList(dataSumParam);
            List<IndexDataSumVo> sumVoList = dataSumList.stream().map(o->{
                IndexDataSumVo vo = new IndexDataSumVo();
                vo.setName(getDivisionName(param.getLevel(),o));
                vo.setIndexName(o.getName());
                vo.setIndexValue(o.getValue());
                return vo;
            }).collect(Collectors.toList());
            //其他数据
            List<Object> objectList = otherIndexInfo(param);
            queryVo.setDataSumVoList(sumVoList);
            queryVo.setOtherDataList(objectList);
            return queryVo;
        }else if(IndexLevelEnum.GRID.getCode()==param.getLevel()||
                IndexLevelEnum.POI.getCode()==param.getLevel()){
            BiIndexDataParam dataParam = new BiIndexDataParam();
            BeanUtils.copyProperties(param,dataParam);
            List<BiIndexData> dataList =  biIndexDataService.indexDataList(dataParam);
            List<IndexDataVo> voList = dataList.stream().map(o->{
                IndexDataVo vo = new IndexDataVo();
//                vo.setLng(o.getLng());
//                vo.setLat(o.getLat());
//                vo.setGrid(o.getGrid());
//                vo.setValue(o.getValue());
                return vo;
            }).collect(Collectors.toList());
            queryVo.setDataVoList(voList);
            //画像
            List<BiCountryProfile> profiles = new ArrayList<>();
            BiCountryProfile biCountryProfile = new BiCountryProfile();
            profiles.add(biCountryProfile);
            queryVo.setBiCountryProfileList(profiles);
            //其他数据
            List<Object> analysisList =  analysis(param);
            queryVo.setOtherDataList(analysisList);

            return queryVo;
        }else{
            throw new ServiceException(ServerExceptionEnum.INDEX_LEVEL_NOT_EXIST.getCode(),ServerExceptionEnum.INDEX_LEVEL_NOT_EXIST.getMessage());
        }
    }

    public List<Object> otherIndexInfo(QueryParam param) {
        List<Object> result = new ArrayList<>();
        //指标说明
        BiIndexFunctionParam biIndexFunctionParam = new BiIndexFunctionParam();
        biIndexFunctionParam.setIndexTypeId(param.getTypeId());
        List<BiIndexFunction> list = biIndexFunctionService.list(biIndexFunctionParam);
        BiIndexFunction biIndexFunction = list.get(0);
        //基本统计
        IndexValueScope scope = new IndexValueScope();
        scope.setMin(new BigDecimal(65.33));
        scope.setMax(new BigDecimal(867.33));
        result.add(biIndexFunction);
        result.add(scope);
        return result;
    }

    @Override
    public List<Object> analysis(QueryParam param) {
        //根据类型找到对应实现类，计算附加信息
        IndexAnalysisEnum analysisEnum = IndexAnalysisEnum.getBeanName(param.getTypeId().intValue());
        AbstractAdapter abstractAdapter = (AbstractAdapter) applicationContext.getBean(analysisEnum.getBeanName());
        List<Object> list = abstractAdapter.additionData();
        return list;
    }

    /**
     * 获取行政区域名称
     * @author: cy
     * @Date: 2022/8/5 11:19
     **/
    public String getDivisionName(Integer level,BiIndexDataSum dataSum){
        String name = null;
        switch (level){
            case 1:
                name = dataSum.getProvName();
                break;
            case 2:
                name = dataSum.getCityName();
                break;
            case 3:
                name = dataSum.getCountryName();
                break;
            default:
        }
        return name;
    }

    /**
     * 经纬度保留两位小数、缩放比例保留1为小数
     * 如果是划定了具体区域则清空请求中省省市区
     * 方便建立缓存
     * @param param
     */
    private void trimLngLat(QueryParam param){
        String lng1 = param.getLng1();
        String lng2 = param.getLng2();
        String lat1 = param.getLat1();
        String lat2 = param.getLat2();
        if (param.getCustomPolygons() != null) {
            Map<String, String> rectMap = DistanceHelper.maxRectangle(param.getCustomPolygons());
            param.setLng1(rectMap.get("lng1"));
            param.setLng2(rectMap.get("lng2"));
            param.setLat1(rectMap.get("lat1"));
            param.setLat2(rectMap.get("lat2"));
        }
        if (lng1 != null && lat1 != null) {
            if(lng1.compareTo(lng2)>0){
                param.setLng1(lng2);
                param.setLng2(lng1);
            }
            if(lat1.compareTo(lat2)>0){
                param.setLat1(lat2);
                param.setLat2(lat1);
            }
            // 如果框选区域，则不判断省市区
            if(param.isExactLngLat()){
                param.setProvName(null);
                param.setCityName(null);
                param.setCountryName(null);
            }
        }

        if (param.getScale() != null) {
            double scale = new BigDecimal(param.getScale()).setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
            param.setScale(scale);
        }
        if(StringUtils.hasText(param.getLat1())){
            if(!param.isExactLngLat()){
                param.setLat1(new BigDecimal(param.getLat1()).setScale(2,BigDecimal.ROUND_DOWN).toPlainString());
                param.setLat2(new BigDecimal(param.getLat2()).setScale(2,BigDecimal.ROUND_UP).toPlainString());
                param.setLng1(new BigDecimal(param.getLng1()).setScale(2,BigDecimal.ROUND_DOWN).toPlainString());
                param.setLng2(new BigDecimal(param.getLng2()).setScale(2,BigDecimal.ROUND_UP).toPlainString());
            }else{
                // 如果是框选指标，则在缩放比例在大于11.5时，展示所有数据，不进行样本抽取
                if(param.getScale()>11.5){
                    param.setScale(20D);
                }
            }
        }

    }

}
